using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;
using Verse.AI;
using Verse.Sound;



namespace RimWorld{

	
//Special case of AnimalInsanity
public class IncidentWorker_AnimalInsanitySingle : IncidentWorker
{
	private const int FixedPoints = 30; //one squirrel

	public override bool TryExecute( IncidentParms parms )
	{
		var map = (Map)parms.target;

		int maxPoints = 150;
		if( GenDate.DaysPassed < 7 )
			maxPoints = 40;

		//Choose an animal type
		List<Pawn> validAnimals = map.mapPawns.AllPawnsSpawned
							.Where( p => p.RaceProps.Animal
								&& p.kindDef.combatPower <= maxPoints
								&& IncidentWorker_AnimalInsanityMass.AnimalUsable(p) )
							.ToList();

		if( validAnimals.Count == 0 )
			return false;

		Pawn animal = validAnimals.RandomElement();
		IncidentWorker_AnimalInsanityMass.DriveInsane( animal );

		string letter;
		letter = "AnimalInsanitySingle".Translate(  animal.Label );
        Find.LetterStack.ReceiveLetter("LetterLabelAnimalInsanitySingle".Translate(), letter, LetterType.BadUrgent, animal);
		return true;
	}
}






public class IncidentWorker_AnimalInsanityMass : IncidentWorker
{
	public static bool AnimalUsable( Pawn p )
	{
		return p.Spawned
			&& !p.Position.Fogged(p.Map)
			&& (!p.InMentalState || !p.MentalStateDef.IsAggro)
			&& !p.Downed
			&& p.Faction == null;
	}

	public static void DriveInsane( Pawn p )
	{
		p.mindState.mentalStateHandler.TryStartMentalState(MentalStateDefOf.Manhunter, forceWake: true);
	}

	public override bool TryExecute( IncidentParms parms )
	{
		var map = (Map)parms.target;

		if( parms.points <= 0 )
		{
			Log.Error("AnimalInsanity running without points.");
			parms.points = (int)(map.strengthWatcher.StrengthRating * 50);
		}

		float adjustedPoints = parms.points;
		if( adjustedPoints > 250 )
		{
			//Halve the amount of points over 250
			adjustedPoints -= 250;
			adjustedPoints *= 0.5f;
			adjustedPoints += 250;
		}


		//Choose an animal kind
		IEnumerable<PawnKindDef> animalKinds = DefDatabase<PawnKindDef>.AllDefs
												.Where( def => def.RaceProps.Animal
														&& def.combatPower <= adjustedPoints
														&& map.mapPawns.AllPawnsSpawned.Where(p=>p.kindDef == def 
																							&& AnimalUsable(p) ).Count() >= 3 );

		PawnKindDef animalDef;
		if( !animalKinds.TryRandomElement(out animalDef) )
			return false;

		List<Pawn> allUsableAnimals = map.mapPawns.AllPawnsSpawned
												.Where(p=>p.kindDef == animalDef
												&& AnimalUsable(p) )
												.ToList();

		float pointsPerAnimal = animalDef.combatPower;
		float pointsSpent = 0;
		int animalsMaddened = 0;
        Pawn lastAnimal = null;
		allUsableAnimals.Shuffle();
		foreach( Pawn animal in allUsableAnimals )
		{
			if( pointsSpent+pointsPerAnimal > adjustedPoints )
				break;

			DriveInsane(animal);

			pointsSpent += pointsPerAnimal;
			animalsMaddened++;
            lastAnimal = animal;
		}

		//Not enough points/animals for even one animal to be maddened
		if( pointsSpent == 0 )
			return false;

		string letter;
		string letterLabel;
		if( animalsMaddened == 1 )
		{
			letterLabel = "LetterLabelAnimalInsanitySingle".Translate() + ": " + lastAnimal.LabelCap;
			letter = "AnimalInsanitySingle".Translate(  lastAnimal.LabelShort );
		}
		else
		{
			letterLabel = "LetterLabelAnimalInsanityMultiple".Translate() + ": " + animalDef.LabelCap;
			letter = "AnimalInsanityMultiple".Translate(  animalDef.label );
		}

        Find.LetterStack.ReceiveLetter(letterLabel, letter, LetterType.BadUrgent, lastAnimal);

        if( map == Find.VisibleMap )
        {
            SoundDefOf.PsychicPulseGlobal.PlayOneShotOnCamera();
            Find.CameraDriver.shaker.DoShake(1.0f);
        }

		return true;
	}
}

}